library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity link_controllers_tb is
end link_controllers_tb; 

architecture tb of link_controllers_tb is
  
  --------------------------------------------------------------------------------------------------------
  --
  -- components 
  --
  -- components used are defined here
  --
  --------------------------------------------------------------------------------------------------------
  component link_controller is

    port ( clk          		: in  std_logic;
           host_address 		: in  std_logic_vector(31 DownTo 0);
           pixel_value      : in  std_logic;
           data_in_n    		: in  std_logic;
           data_in_ne   		: in  std_logic;
           data_in_nw   		: in  std_logic;
           data_in_s    		: in  std_logic;
           data_in_se   		: in  std_logic;
           data_in_sw   		: in  std_logic;
           data_in_e    		: in  std_logic;
           data_in_w    		: in  std_logic;
           data_out_n   		: out std_logic;
           data_out_ne  		: out std_logic;
           data_out_nw  		: out std_logic;
           data_out_s   		: out std_logic;
           data_out_se  		: out std_logic;
           data_out_sw  		: out std_logic;
           data_out_e   		: out std_logic;
           data_out_w   		: out std_logic;
           links_complete   : out std_logic;
           controller_label : out std_logic_vector(31 DownTo 0)
         );
   
  end component;

  component link_physical is

    port ( link_a   : in  std_logic;
           link_b   : in  std_logic;
           or_out   : out std_logic
         );

  end component;

  --------------------------------------------------------------------------------------------------------
  --
  -- global signals
  --
  -- all global signals used across controllers are defined here
  --
  --------------------------------------------------------------------------------------------------------
  signal controller_clk 											: std_logic;
  signal physical_link_1_2              			: std_logic;
  signal physical_link_2_3              			: std_logic;

  --------------------------------------------------------------------------------------------------------
  --
  -- controller signals
  --
  -- all controller signals are defined here
  --
  --------------------------------------------------------------------------------------------------------

  -- link 1 signals
  signal link_1_out_n          								: std_logic;
  signal link_1_out_ne         								: std_logic;
  signal link_1_out_nw         								: std_logic;
  signal link_1_out_s          								: std_logic;
  signal link_1_out_se         								: std_logic;
  signal link_1_out_sw         								: std_logic;
  signal link_1_out_e          								: std_logic;
  signal link_1_out_w          								: std_logic;      

  signal link_1_address  								      : std_logic_vector(31 DownTo 0);
  signal link_1_controller_pixel    			    : std_logic;
  signal link_1_controller_complete 			    : std_logic;
  signal link_1_controller_final_label        : std_logic_vector(31 DownTo 0);

  signal dummy_link_1_n                       : std_logic;
  signal dummy_link_1_ne                      : std_logic;
  signal dummy_link_1_nw                      : std_logic;
  signal dummy_link_1_se                      : std_logic;
  signal dummy_link_1_sw                      : std_logic;
  signal dummy_link_1_e                       : std_logic;
  signal dummy_link_1_w                       : std_logic;

  -- link 2 signals
  signal link_2_out_n          								: std_logic;
  signal link_2_out_ne         								: std_logic;
  signal link_2_out_nw         								: std_logic;
  signal link_2_out_s          								: std_logic;
  signal link_2_out_se         								: std_logic;
  signal link_2_out_sw         								: std_logic;
  signal link_2_out_e          								: std_logic;
  signal link_2_out_w          								: std_logic;

  signal link_2_address  								      : std_logic_vector(31 DownTo 0);
  signal link_2_controller_pixel    			    : std_logic;
  signal link_2_controller_complete 			    : std_logic;
  signal link_2_controller_final_label        : std_logic_vector(31 DownTo 0);
  signal dummy_link_1_g                       : std_logic;

  signal dummy_link_2_ne                      : std_logic;
  signal dummy_link_2_nw                      : std_logic;
  signal dummy_link_2_s                       : std_logic;
  signal dummy_link_2_se                      : std_logic;
  signal dummy_link_2_sw                      : std_logic;
  signal dummy_link_2_e                       : std_logic;
  signal dummy_link_2_w                       : std_logic;

  -- link 3 signals
  signal link_3_out_n          								: std_logic;
  signal link_3_out_ne         								: std_logic;
  signal link_3_out_nw         								: std_logic;
  signal link_3_out_s          								: std_logic;
  signal link_3_out_se         								: std_logic;
  signal link_3_out_sw         								: std_logic;
  signal link_3_out_e          								: std_logic;
  signal link_3_out_w          								: std_logic;      

  signal link_3_address  								      : std_logic_vector(31 DownTo 0);
  signal link_3_controller_pixel    			    : std_logic;
  signal link_3_controller_complete 			    : std_logic;
  signal link_3_controller_final_label        : std_logic_vector(31 DownTo 0);

  signal dummy_link_3_n                       : std_logic;
  signal dummy_link_3_ne                      : std_logic;
  signal dummy_link_3_nw                      : std_logic;
  signal dummy_link_3_s                       : std_logic;
  signal dummy_link_3_se                      : std_logic;
  signal dummy_link_3_sw                      : std_logic;
  signal dummy_link_3_e                       : std_logic;

begin

  --------------------------------------------------------------------------------------------------------
  --
  -- controllers
  --
  -- all controllers are set up here
  --
  --------------------------------------------------------------------------------------------------------
  link_controller_1 : link_controller port map ( controller_clk,
                                                 link_1_address,
                                                 link_1_controller_pixel,
                                                 dummy_link_1_n,
                                                 dummy_link_1_ne,
                                                 dummy_link_1_nw,
                                                 physical_link_1_2,
                                                 dummy_link_1_se,
                                                 dummy_link_1_sw,
                                                 dummy_link_1_e,
                                                 dummy_link_1_w,
                                                 link_1_out_n,
                                                 link_1_out_ne,
                                                 link_1_out_nw,
                                                 link_1_out_s,
                                                 link_1_out_se,
                                                 link_1_out_sw,
                                                 link_1_out_e,
                                                 link_1_out_w,
                                                 link_1_controller_complete,
                                                 link_1_controller_final_label
                                               );

  link_controller_2 : link_controller port map ( controller_clk,
                                                 link_2_address,
                                                 link_2_controller_pixel,
                                                 physical_link_1_2,
                                                 dummy_link_2_ne,
                                                 dummy_link_2_nw,
                                                 dummy_link_2_s,
                                                 dummy_link_2_se,
                                                 dummy_link_2_sw,
                                                 physical_link_2_3,
                                                 dummy_link_2_w,
                                                 link_2_out_n,
                                                 link_2_out_ne,
                                                 link_2_out_nw,
                                                 link_2_out_s,
                                                 link_2_out_se,
                                                 link_2_out_sw,
                                                 link_2_out_e,
                                                 link_2_out_w,
                                                 link_2_controller_complete,
                                                 link_2_controller_final_label
                                               );

  link_controller_3 : link_controller port map ( controller_clk,
                                                 link_3_address,
                                                 link_3_controller_pixel,
                                                 dummy_link_3_n,
                                                 dummy_link_3_ne,
                                                 dummy_link_3_nw,
                                                 dummy_link_3_s,
                                                 dummy_link_3_se,
                                                 dummy_link_3_sw,
                                                 dummy_link_3_e,
                                                 physical_link_2_3,
                                                 link_3_out_n,
                                                 link_3_out_ne,
                                                 link_3_out_nw,
                                                 link_3_out_s,
                                                 link_3_out_se,
                                                 link_3_out_sw,
                                                 link_3_out_e,
                                                 link_3_out_w,
                                                 link_3_controller_complete,
                                                 link_3_controller_final_label
                                               );

  --------------------------------------------------------------------------------------------------------
  --
  -- dummy links
  --
  -- all dummy links are set in this section
  --
  --------------------------------------------------------------------------------------------------------

  -- dummy links for controller 1
  link_1_dummy_n  : link_physical port map ( link_1_out_n , link_1_out_n , dummy_link_1_n  );
  link_1_dummy_ne : link_physical port map ( link_1_out_ne, link_1_out_ne, dummy_link_1_ne );
  link_1_dummy_nw : link_physical port map ( link_1_out_nw, link_1_out_nw, dummy_link_1_nw );
  link_1_dummy_se : link_physical port map ( link_1_out_se, link_1_out_se, dummy_link_1_se );
  link_1_dummy_sw : link_physical port map ( link_1_out_sw, link_1_out_sw, dummy_link_1_sw );
  link_1_dummy_e  : link_physical port map ( link_1_out_e , link_1_out_e , dummy_link_1_e  );
  link_1_dummy_w  : link_physical port map ( link_1_out_w , link_1_out_w , dummy_link_1_w  );

  -- dummy links for controller 2
  link_2_dummy_ne : link_physical port map ( link_2_out_ne, link_2_out_ne, dummy_link_2_ne );
  link_2_dummy_nw : link_physical port map ( link_2_out_nw, link_2_out_nw, dummy_link_2_nw );
  link_2_dummy_s  : link_physical port map ( link_2_out_s , link_2_out_s , dummy_link_2_s  );
  link_2_dummy_se : link_physical port map ( link_2_out_se, link_2_out_se, dummy_link_2_se );
  link_2_dummy_sw : link_physical port map ( link_2_out_sw, link_2_out_sw, dummy_link_2_sw );
  link_2_dummy_e  : link_physical port map ( link_2_out_e , link_2_out_e , dummy_link_2_e  );
  link_2_dummy_w  : link_physical port map ( link_2_out_w , link_2_out_w , dummy_link_2_w  );

  -- dummy links for controller 3
  link_3_dummy_n  : link_physical port map ( link_3_out_n , link_3_out_n , dummy_link_3_n  );
  link_3_dummy_ne : link_physical port map ( link_3_out_ne, link_3_out_ne, dummy_link_3_ne );
  link_3_dummy_nw : link_physical port map ( link_3_out_nw, link_3_out_nw, dummy_link_3_nw );
  link_3_dummy_s  : link_physical port map ( link_3_out_s , link_3_out_s , dummy_link_3_s  );
  link_3_dummy_se : link_physical port map ( link_3_out_se, link_3_out_se, dummy_link_3_se );
  link_3_dummy_sw : link_physical port map ( link_3_out_sw, link_3_out_sw, dummy_link_3_sw );
  link_3_dummy_e  : link_physical port map ( link_3_out_e , link_3_out_e , dummy_link_3_e  );


  --------------------------------------------------------------------------------------------------------
  --
  -- physical links
  --
  -- all physical links are set in this section
  --
  --------------------------------------------------------------------------------------------------------

  link_1_2        : link_physical port map ( link_1_out_s , link_2_out_n , physical_link_1_2 );
  link_2_3        : link_physical port map ( link_2_out_e , link_3_out_w , physical_link_2_3 );

                                                 
  process

    variable out_loop : integer := 0;

    procedure clock_link is
    begin
      controller_clk <= '1';
      wait for 1 ns;
      controller_clk <= '0';
      wait for 1 ns;
    end clock_link;

    procedure print_any_label ( print_label : std_logic_vector ) is
    begin

      report ("Printing Final Label: " & std_logic'image(print_label(31))
                                       & std_logic'image(print_label(30))
                                       & std_logic'image(print_label(29))
                                       & std_logic'image(print_label(28))
                                       & std_logic'image(print_label(27))
                                       & std_logic'image(print_label(26))
                                       & std_logic'image(print_label(25))
                                       & std_logic'image(print_label(24))
                                       & std_logic'image(print_label(23))
                                       & std_logic'image(print_label(22))
                                       & std_logic'image(print_label(21))
                                       & std_logic'image(print_label(20))
                                       & std_logic'image(print_label(19))
                                       & std_logic'image(print_label(18))
                                       & std_logic'image(print_label(17))
                                       & std_logic'image(print_label(16))
                                       & std_logic'image(print_label(15))
                                       & std_logic'image(print_label(14))
                                       & std_logic'image(print_label(13))
                                       & std_logic'image(print_label(12))
                                       & std_logic'image(print_label(11))
                                       & std_logic'image(print_label(10))
                                       & std_logic'image(print_label(9))
                                       & std_logic'image(print_label(8))
                                       & std_logic'image(print_label(7))
                                       & std_logic'image(print_label(6))
                                       & std_logic'image(print_label(5))
                                       & std_logic'image(print_label(4))
                                       & std_logic'image(print_label(3))
                                       & std_logic'image(print_label(2))
                                       & std_logic'image(print_label(1))
                                       & std_logic'image(print_label(0)));

    end procedure print_any_label;

    procedure print_all_final_labels is
    begin

      print_any_label(link_1_controller_final_label);
      print_any_label(link_2_controller_final_label);
      print_any_label(link_3_controller_final_label);

    end procedure print_all_final_labels;

    impure function are_all_controllers_complete return std_logic is
      variable result : std_logic := '1';
    begin

      result := result and link_1_controller_complete;
      result := result and link_2_controller_complete;
      result := result and link_3_controller_complete;

      return result;

    end function are_all_controllers_complete;

  begin

    --------------------------------------------------------------------------------------------------------
    --
    -- set controller pixel values
    --
    --------------------------------------------------------------------------------------------------------
    link_1_controller_pixel <= '1';
    link_2_controller_pixel <= '1';
    link_3_controller_pixel <= '1';
    wait for 1 ns;

    --------------------------------------------------------------------------------------------------------
    --
    -- set controller addresses
    --
    --------------------------------------------------------------------------------------------------------
    link_1_address <= "00000000000000000000000000000001";
    link_2_address <= "00000000000000000000000000011110";
    link_3_address <= "00000000000000000000000000011111";
    wait for 1 ns;

    --------------------------------------------------------------------------------------------------------
    --
    -- initialize all links with 3 clock cycles
    --
    --------------------------------------------------------------------------------------------------------
    clock_link;
    clock_link;
    clock_link;

    while are_all_controllers_complete = '0' loop

      out_loop := out_loop + 1;
      report ("Clocking Com: " & integer'image(out_loop));

      clock_link;
      clock_link;

      -- link reset is read on this cycle

      clock_link;
      clock_link;
      clock_link;
      
      -- link data set on this clock cycle

      clock_link;
      clock_link;
      clock_link;

      clock_link;
      clock_link;

      clock_link;
      clock_link;
      clock_link;


    end loop;

    --------------------------------------------------------------------------------------------------------
    --
    -- print out final labels
    --
    --------------------------------------------------------------------------------------------------------
    report ("Number Of Communication Cycles to Converge: " & integer'image( out_loop ));
    print_all_final_labels;

    wait;

  end process;

end tb;
